#ifndef __BUOLA_GUI_X11_ICCCM_H__
#define __BUOLA_GUI_X11_ICCCM_H__

#include <buola/gui/x11/auto.h>
#include <buola/gui/x11/cx11toolkit.h>
#include <buola/gui/cwindow.h>

namespace buola { namespace gui { namespace x11 { namespace icccm {

////////////////////////////////// structures and constants //////////////////////////////////////

/////////////////////////////
// ICCCM client properties
//

///from an ICCCM point of view, the client can be in one of three
///states, which are specified in this enum
enum EWMState
{
    WMSTATE_WITHDRAWN,
    WMSTATE_ICONIC,
    WMSTATE_NORMAL
};

enum ESizeHints
{
    SIZEHINT_NONE=0,
    HINT_FIXED=(1<<0),
    HINT_MAX=(1<<1),
    HINT_MIN=(1<<2),
    HINT_BASE=(1<<3),
    HINT_RESIZE=(1<<4),
    HINT_USERPOS=(1<<5),
    HINT_PROGRAMPOS=(1<<6),
    HINT_USERSIZE=(1<<7),
    HINT_PROGRAMSIZE=(1<<8)
};

DECLARE_ENUM_BITOPS(ESizeHints)

enum EWMHints
{
    WMHINT_NONE=0,
    HINT_WANTSFOCUS=(1<<0),
    HINT_URGENCY=(1<<1)
};

DECLARE_ENUM_BITOPS(EWMHints)

enum EWMProtocols
{
    PROTOCOL_NONE=0,
    PROTOCOL_DELETE=(1<<0),
    PROTOCOL_TAKEFOCUS=(1<<1),
    PROTOCOL_SYNCREQUEST=(1<<2),
    PROTOCOL_CONTEXTHELP=(1<<3),

    PROTOCOL_ALLBUOLA=PROTOCOL_DELETE|PROTOCOL_TAKEFOCUS|PROTOCOL_CONTEXTHELP
};

DECLARE_ENUM_BITOPS(EWMProtocols)

struct CSizeHints
{
    ESizeHints mFlags;
    
    CSize_i mMin;
    CSize_i mMax;
    CSize_i mBase;
    CSize_i mInc;
    int mMinAspect;
    int mMaxAspect;
};

struct CWMHints
{
    EWMHints mFlags;
    
    Pixmap mIconPixmap;
    Pixmap mIconMask;
    Window mGroupLeader;
};

/////////////////////////////
// motif client properties
//

#define MOTIF_FUNCTIONS             (1 << 0)
#define MOTIF_DECORATIONS           (1 << 1)
#define MOTIF_INPUT_MODE            (1 << 2)
#define MOTIF_STATUS                (1 << 3)

#define MOTIF_FUNCTION_ALL          (1 << 0)
#define MOTIF_FUNCTION_RESIZE       (1 << 1)
#define MOTIF_FUNCTION_MOVE         (1 << 2)
#define MOTIF_FUNCTION_MINIMIZE     (1 << 3)
#define MOTIF_FUNCTION_MAXIMIZE     (1 << 4)
#define MOTIF_FUNCTION_CLOSE        (1 << 5)

#define MOTIF_DECOR_ALL             (1 << 0)
#define MOTIF_DECOR_BORDER          (1 << 1)
#define MOTIF_DECOR_RESIZEH         (1 << 2)
#define MOTIF_DECOR_TITLE           (1 << 3)
#define MOTIF_DECOR_MENU            (1 << 4)
#define MOTIF_DECOR_MINIMIZE        (1 << 5)
#define MOTIF_DECOR_MAXIMIZE        (1 << 6)

#define MOTIF_INPUT_MODELESS        0
#define MOTIF_INPUT_APPMODAL        1
#define MOTIF_INPUT_MODAL           2
#define MOTIF_INPUT_FULLMODAL       3

#define MOTIF_HINTS_COUNT           5

struct CMotifHints
{
    unsigned long mFlags;
    unsigned long mFunctions;
    unsigned long mDecorations;
    long mInputMode;
    unsigned long mStatus;
};

///////////////////////////
// NET client properties
//

enum ENetState
{
    NETSTATE_NONE=0,
    NETSTATE_STICKY=(1<<0),
    NETSTATE_ABOVE=(1<<1),
    NETSTATE_BELOW=(1<<2),
    NETSTATE_SKIPTASKBAR=(1<<3),
    NETSTATE_SKIPPAGER=(1<<4),
    NETSTATE_MODAL=(1<<5),
    NETSTATE_MAXHORZ=(1<<6),
    NETSTATE_MAXVERT=(1<<7),
    NETSTATE_SHADED=(1<<8),
    NETSTATE_HIDDEN=(1<<9),
    NETSTATE_FULLSCREEN=(1<<10)
};

DECLARE_ENUM_BITOPS(ENetState)

#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
#define _NET_WM_MOVERESIZE_SIZE_TOP          1
#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT     2
#define _NET_WM_MOVERESIZE_SIZE_RIGHT        3
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT  4
#define _NET_WM_MOVERESIZE_SIZE_BOTTOM       5
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT   6
#define _NET_WM_MOVERESIZE_SIZE_LEFT         7
#define _NET_WM_MOVERESIZE_MOVE              8   /* movement only */
#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD     9   /* size via keyboard */
#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD    10   /* move via keyboard */

/////////////////////////////////////// read functionality ///////////////////////////////////////

/////////////////////////////
// ICCCM client properties
//

std::wstring read_wm_name(Window pID,CX11Display *pDisplay=get_default_x11_display());
std::string read_wm_class(Window pID,CX11Display *pDisplay=get_default_x11_display());
std::string read_wm_client_machine(Window pID,CX11Display *pDisplay=get_default_x11_display());
bool read_wm_normal_hints(Window pID,CSizeHints &pHints,CX11Display *pDisplay=get_default_x11_display());
bool read_wm_hints(Window pID,CWMHints &pHints,CX11Display *pDisplay=get_default_x11_display());
Window read_wm_transient_for(Window pID,CX11Display *pDisplay=get_default_x11_display());
EWMProtocols read_wm_protocols(Window pID,CX11Display *pDisplay=get_default_x11_display());
EWMState read_wm_state(Window pID,CX11Display *pDisplay=get_default_x11_display());

/////////////////////////////
// motif client properties
//

bool read_motif_hints(Window pID,CMotifHints &pHints,CX11Display *pDisplay=get_default_x11_display());

///////////////////////////
// NET client properties
//

std::wstring read_net_wm_name(Window pID,CX11Display *pDisplay=get_default_x11_display());
bool read_net_wm_desktop(Window pID,unsigned int &pValue,CX11Display *pDisplay=get_default_x11_display());
ENetState read_net_wm_state(Window pID,CX11Display *pDisplay=get_default_x11_display());
EWindowType read_net_wm_window_type(Window pID,CX11Display *pDisplay=get_default_x11_display());
CRect_i read_net_wm_strut(Window pID,CX11Display *pDisplay=get_default_x11_display());
CRect_i read_net_wm_icon_geometry(Window pID,CX11Display *pDisplay=get_default_x11_display());
bool read_net_wm_icon(Window pID,std::vector<img::CPicture> &pIcons,CX11Display *pDisplay=get_default_x11_display());
double read_net_wm_window_opacity(Window pID,CX11Display *pDisplay=get_default_x11_display());

///////////////////////////
// NET root properties
//

bool read_net_client_list_stacking(std::vector<Window> &pList,CX11Display *pDisplay=get_default_x11_display(),
                                   Window pID=-1);
Window read_net_active_window(CX11Display *pDisplay=get_default_x11_display(),Window pID=-1);
int read_net_number_of_desktops(CX11Display *pDisplay=get_default_x11_display(),Window pID=-1);
int read_net_current_desktop(CX11Display *pDisplay=get_default_x11_display(),Window pID=-1);
CSize_i read_net_desktop_geometry(CX11Display *pDisplay=get_default_x11_display(),Window pID=-1);
bool read_net_desktop_viewport(std::vector<CPoint_i> &pViewports,CX11Display *pDisplay=get_default_x11_display(),
                               Window pID=-1);
bool read_net_workarea(std::vector<CRect_i> &pWorkAreas,CX11Display *pDisplay=get_default_x11_display(),Window pID=-1);

/////////////////////////////////////// write functionality ///////////////////////////////////////

/////////////////////////////
// ICCCM client properties
//

void write_wm_state(Window pID,EWMState pState,CX11Display *pDisplay=get_default_x11_display());
void write_wm_protocols(Window pID,EWMProtocols pProtocols,CX11Display *pDisplay=get_default_x11_display());
void write_wm_command(Window pID,const std::string &pCommand=get_application_name(),
                      CX11Display *pDisplay=get_default_x11_display());
void write_wm_client_machine(Window pID,const std::string &pHost=get_host_name(),
                             CX11Display *pDisplay=get_default_x11_display());
void write_wm_class(Window pID,const std::string &pClass=get_application_name(),
                    const std::string &pSubClass=get_application_name(),CX11Display *pDisplay=get_default_x11_display());
void write_wm_icon_name(Window pID,const std::string &pIconName,CX11Display *pDisplay=get_default_x11_display());

///////////////////////////
// NET client properties
//

void write_net_wm_desktop(Window pID,unsigned int pDesktop,CX11Display *pDisplay=get_default_x11_display());
void write_net_wm_state(Window pID,ENetState pState,CX11Display *pDisplay=get_default_x11_display());
void write_net_wm_icon_geometry(Window pID,const CRect_i &pRect,CX11Display *pDisplay=get_default_x11_display());
void write_net_frame_extents(Window pID,const CRect_i &pExtents,CX11Display *pDisplay=get_default_x11_display());
void write_net_wm_visible_name(Window pID,const std::wstring &pVisibleName,CX11Display *pDisplay=get_default_x11_display());
void write_net_wm_sync_request_counter(Window pID,int pCounter,CX11Display *pDisplay=get_default_x11_display());
void write_net_wm_window_type(Window pID,EWindowType pClass,CX11Display *pDisplay=get_default_x11_display());

/////////////////////////
// NET root properties
//

void write_net_supporting_wm_check(Window pID,CX11Display *pDisplay=get_default_x11_display(),Window pRootID=-1);
void write_net_supported(CX11Display *pDisplay=get_default_x11_display(),Window pID=-1);

/*namespace icccm */ } /*namespace x11*/ } /*namespace gui*/ } /*namespace buola*/ }

#endif
